-- Viral Resistance - T-Engine 4 Module
-- Copyright (C) 2010 Mikolai Fajer
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
--
-- Mikolai Fajer "yufra"
-- mfajer@gmail.com

require "engine.class"
local Map = require "engine.Map"
local Target = require "engine.Target"
local DamageType = require "engine.DamageType"

--- Handles actors life and death
module(..., package.seeall, class.make)

function _M:init(t)
	self.max_life = t.max_life or 100
	self.life = t.life or self.max_life
	self.life_regen = t.life_regen or 0
	self.max_vload = t.max_vload or 100
	self.vload = t.vload or 0
	self.vload_regen = t.vload_regen or 0
end

--- Checks if something bumps in us
-- If it happens the method attack is called on the target with the attacker as parameter.
-- Do not touch!
function _M:block_move(x, y, e, can_attack)
	-- Dont bump yourself!
	if e and e ~= self and can_attack then
		e:attack(self)
	end
	return true
end

--- Regenerate life, call it from your actor class act() method
function _M:regenLife()
	if self.life_regen then
		self.life = util.bound(self.life + self.life_regen, 0, self.max_life)
	end
end

--- Regenerate viral load, call it from your actor class act() method
function _M:regenVload()
	if self.vload == 0 then return end
	if self.vload_regen > 0 and rng.percent(self.vload) then
		self:takeVloadHit(self.vload_regen, {name="Viral contamination"})
	else
		self:healVload(self.vload_regen)
	end
end

--- Heal some
function _M:heal(value, src)
	self.life = util.bound(self.life + value, 0, self.max_life)
	self.changed = true
end

--- Heal some viral load
function _M:healVload(value, src)
	self.vload = util.bound(self.vload + value, 0, self.max_vload)
	self.changed = true
end

--- Remove some HP from an actor
-- If HP is reduced to 0 then remove from the level and call the die method.<br/>
-- When an actor dies its dead property is set to true, to wait until garbage collection deletes it
function _M:takeHit(value, src)
	if self.onTakeHit then value = self:onTakeHit(value, src) end
	self.life = self.life - value
	self.changed = true
	if self.life <= 0 then
		game.level.map:particleEmitter(self.x, self.y, 1, "blood")
		game.logSeen(self, "%s killed %s!", src.name:capitalize(), self.name)
		return self:die(src)
	end
end

--- Adds some VL from an actor
-- If VL is increased to max_vload then remove from the level and call the die method.<br/>
-- When an actor dies its dead property is set to true, to wait until garbage collection deletes it
function _M:takeVloadHit(value, src)
	if self.onTakeVloadHit then value = self:onTakeVloadHit(value, src) end
	self.vload = self.vload + value
	self.changed = true
	if self.vload >= self.max_vload then
		if self.mutation then
			local mutation_name
			if type(self.mutation) == "table" then
				-- Assumes a table of NAME=rarity pairs
				local normalization = 0
				for k, v in pairs(self.mutation) do
					normalization = v + normalization
				end
				local cumulative_prob = 0
				local selection = rng.float(0, 100)
				for k, v in pairs(self.mutation) do
					cumulative_prob = v / normalization * 100 + cumulative_prob
					if selection <= cumulative_prob then
						mutation_name = k
						break
					end
				end
			else
				mutation_name = self.mutation
			end
			game.logSeen(self, "%s caused a mutation in %s!", src.name:capitalize(), self.name)
			self:die(src, true)
			local z = game.zone:makeEntityByName(game.level, "actor", mutation_name)
			game.zone:addEntity(game.level, z, "actor", self.x, self.y)
			game.level.map:particleEmitter(self.x, self.y, 1, "viral")
			game.logSeen(self, "%s just turned into a %s!", self.name, z.name)
			-- Change new zombie's health to reflect the percentage of the old zombie
			local percent_health = self.life / self.max_life
			z.life = z.life * percent_health
		elseif self.type ~= "zombie" then
			game.logSeen(self, "%s succumbed to the virus!", self.name)
			self:die(src)
		end
	end
end

--- Called when died
function _M:die(src)
	game.level:removeEntity(self)
	self.dead = true
	self.changed = true

	self:check("on_die", src)
end

--- Actor is being attacked!
-- Module authors should rewrite it to handle combat, dialog, ...
-- @param target the actor attacking us
function _M:attack(target)
	game.logSeen(target, "%s attacks %s.", self.name:capitalize(), target.name:capitalize())
	target:takeHit(10, self)
end
